import EventType from "../../model/EventType";
import EventManage from "../event/EventManage";
import PoolObj from "../pool/PoolObj";
import { Logger } from "../log/logger";
import MathUtils from "../utils/MathUtils";
import Utils from "../utils/Utils";

export class SoundItem {

    static create(): SoundItem {
        return PoolObj.getItemByClass("_sounditem_", SoundItem);
    }

    static recover(obj: SoundItem) {
        PoolObj.recover("_sounditem_", obj);
    }

    //============================================================

    /** 0播放中 1停止中 2已停止*/
    private _state: number;

    /**播放参数 */
    protected _opt: SoundOption;

    /**播放源 */
    protected _source: Laya.SoundChannel;

    /**声音缓动 */
    private _volumeTween: Laya.Tween;

    /**基础音量（系统音量缩放*type音量缩放） */
    private _baseVolume: number = 100;

    public url: string;
    public type: number = 0;
    public complete: Laya.Handler;

    play(url: string, opt?: SoundOption) {
        this.initOpt(opt, url === this.url);
        this.url = url;
        this._state = 0;
        this._source = this._play();
        this.fadeVolume(true)
    }

    stop(slow: boolean = true) {

        if (this._opt.fadeOut > 0 && slow) {
            this.fadeVolume(false, Laya.Handler.create(this, _stop))
        } else {
            _stop.call(this);
        }

        function _stop(this: SoundItem) {

            Logger.logView(this._source, "声音结束：")

            let s = this._source;
            this._state = 2;
            let url = this.url, type = this.type;


            if (this._volumeTween) {
                this._volumeTween.clear();
                this._volumeTween = null;
            }

            if (s == null) {
                this._opt = this.url = null;
                SoundItem.recover(this);
                return;
            }

            if (!s.isStopped) {
                s.stop();
                this._source = null
            }

            EventManage.I.event(EventType.SOUND_STOP, [url, type])
            this.complete && this.complete.run();

            SoundItem.recover(this);
        }
    }

    fadeVolume(fadein: boolean, compleat: Laya.Handler = null) {
        if (this._volumeTween) {
            this._volumeTween.clear();
        }

        let v = 0, d = 0;
        if (fadein && this._opt.fadeIn > 0) {
            this._source.volume = 0;
            d = this._opt.fadeIn;
            v = this.volume;
        }

        if (!fadein && this._opt.fadeOut > 0) {
            this._source.volume = this.volume;
            d = this._opt.fadeOut;
            v = 0;
        }

        if (d == 0) {
            compleat && compleat.run();
            this.updateVolume();
        } else {
            this._volumeTween = Laya.Tween.to(this._source, { volume: v }, d, null, compleat);
        }
    }

    updateVolume() {
        if (!this._source) return;
        this._source.volume = this.volume;
    }

    public get volume() {
        return Utils.lerpScale(this._baseVolume, 100, this._opt.volume)
    }

    public set baseValume(v: number) {
        this._baseVolume = v;
        this.updateVolume();
    }

    public get channel() {
        return this._source;
    }

    //总时间
    public get duration() {
        return this._source.duration
    }

    public get opt(): Readonly<SoundOption> {
        return this._opt;
    }

    protected _play() {
        let opt = this._opt;
        let elm = Laya.SoundManager.playSound(this.url, opt.loop, Laya.Handler.create(this, this.onComplete), null, opt.start);
        return elm
    }

    protected onComplete() {
        if (this._state == 2) return;
        this.stop(false);
    }

    private initOpt(opt: SoundOption, reuse: boolean): SoundOption {

        if (reuse && this._opt != null) {
            return this._opt;
        }

        opt = opt == null ? {} : opt;
        let vl = 1, loop = 1, prio = 10, fin = 0, fout = 0, st = 0;
        this._opt = {
            volume: opt.volume || vl,
            loop: opt.loop || loop,
            priority: opt.priority || prio,
            fadeIn: opt.fadeIn || fin,
            fadeOut: opt.fadeOut || fout,
            start: opt.start || st
        }

        return this._opt;
    }
}

export class soundMusic extends SoundItem {

    static create(): soundMusic {
        return PoolObj.getItemByClass("_soundMusic_", soundMusic);
    }

    static recover(obj: soundMusic) {
        PoolObj.recover("_soundMusic_", obj);
    }

    protected _play(): laya.media.SoundChannel {
        let opt = this._opt;
        let elm = Laya.SoundManager.playMusic(this.url, opt.loop, Laya.Handler.create(this, this.onComplete), opt.start);
        return elm
    }
}

export interface SoundOption {
    volume?: number;    //播放音量0-100
    loop?: number;      //循环次数 0为无限循环 默认1次
    priority?: number;  //优先级 数值越大优先级高
    fadeIn?: number;    //淡入时长
    fadeOut?: number;   //淡出时长
    start?: number;     //播放起自随机时点。
}